﻿///////////////////////////////////////////////////////////////////////////////
// Copyright 2016 lingzimaike@gmail.com
// GPLv2
// Author: lingzimaike
///////////////////////////////////////////////////////////////////////////////

#include "papa/util/xml_file.h"
#include "papa/util/string.h"

namespace papa {
namespace util {

    XmlFile::XmlFile(void)
        : doc_()
        , file_name_("")
    {

    }

    XmlFile::~XmlFile(void)
    {

    }

    bool XmlFile::Load(const char* file_name, Encoding encoding /* = kDefaultEncoding */)
    {
        return doc_.LoadFile(file_name, (TiXmlEncoding)encoding);
    }

    XmlFile* XmlFile::Create(const char* file_name, const char* version /* = "1.0" */, 
        const char* encoding /* = "utf8" */, const char* standalone /* = "no" */)
    {
        XmlFile* doc = new XmlFile();
        if (doc)
        {
            TiXmlDeclaration* declare = new TiXmlDeclaration(version, encoding, standalone);
            if (declare)
            {
                doc->doc_.LinkEndChild(declare);
                doc->file_name_ = file_name;
                return doc;
            }
            delete doc;
        }
        return NULL;
    }

    XmlFile::Node* XmlFile::Find(const char* path)
    {
        Tokens tokens = StrSplit(path, ".");
        Node* node = GetRootNode();
        Tokens::const_iterator token = tokens.begin();
        for (; token != tokens.end(); ++token)
        {
            node = node->FirstChildElement(token->c_str());
            if (node == NULL) {
                break;
            }
        }
        return node;
    }

    XmlFile::Node* XmlFile::FindOrCreate(const char* path)
    {
        Tokens tokens = StrSplit(path, ".");
        Node* node = GetRootNode();
        Tokens::const_iterator token = tokens.begin();
        for (; token != tokens.end(); ++token)
        {
            Node* tmp = node->FirstChildElement(token->c_str());
            if (tmp == NULL)
            {
                tmp = CreateNode(token->c_str());
                if (tmp)
                {
                    node->LinkEndChild(tmp);
                    node = tmp;
                    continue;
                }
                return NULL;
            }
            else {
                node = tmp;
            }
        }
        return node;
    }

    const char* XmlFile::GetText(const char* path, const char* default /* = "" */)
    {
        Node* node = Find(path);
        if (node)
        {
            TiXmlNode* text = node->FirstChild();
            if (text->Type() == TiXmlNode::TINYXML_TEXT) {
                return text->ToText()->Value();
            }
        }
        return default;
    }

    int XmlFile::GetInt(const char* path, int default /* = 0 */)
    {
        Node* node = Find(path);
        if (node)
        {
            TiXmlNode* text = node->FirstChild();
            if (text->Type() == TiXmlNode::TINYXML_TEXT) {
                return atoi(text->ToText()->Value());
            }
        }
        return default;
    }

    long XmlFile::GetLong(const char* path, long default /* = 0 */)
    {
        Node* node = Find(path);
        if (node)
        {
            TiXmlNode* text = node->FirstChild();
            if (text->Type() == TiXmlNode::TINYXML_TEXT)
            {
                return atol(text->ToText()->Value());
            }
        }
        return default;
    }

    double XmlFile::GetDouble(const char* path, double default /* = 0.0f */)
    {
        Node* node = Find(path);
        if (node)
        {
            TiXmlNode* text = node->FirstChild();
            if (text->Type() == TiXmlNode::TINYXML_TEXT)
            {
                return atof(text->ToText()->Value());
            }
        }
        return default;
    }

    bool XmlFile::SetText(const char* path, const char* value)
    {
        Node* node = FindOrCreate(path);
        if (node)
        {
            TiXmlNode* text = node->FirstChild();
            if (text == NULL)
            {
                text = new Text(value);
                if (text)
                {
                    node->LinkEndChild(text);
                    return true;
                }
            }
            else if (text->Type() == TiXmlNode::TINYXML_TEXT)
            {
                text->ToText()->SetValue(value);
                return true;
            }
        }
        return false;
    }

    bool XmlFile::SetInt(const char* path, int value)
    {
        char buf[32] = { 0 };
        Node* node = FindOrCreate(path);
        if (node)
        {
            TiXmlNode* text = node->FirstChild();
            if (text == NULL)
            {
#if defined(__WINDOWS__)
                _itoa_s(value, buf, sizeof(buf), 10);
#else
                itoa(value, buf, 10);
#endif
                text = new Text(buf);
                if (text)
                {
                    node->LinkEndChild(text);
                    return true;
                }
            }
            else if (text->Type() == TiXmlNode::TINYXML_TEXT)
            {
#if defined(__WINDOWS__)
                _itoa_s(value, buf, sizeof(buf), 10);
#else
                itoa(value, buf, 10);
#endif
                text->ToText()->SetValue(buf);
                return true;
            }
        }
        return false;
    }

    bool XmlFile::SetLong(const char* path, long value)
    {
        char buf[32] = { 0 };
        Node* node = FindOrCreate(path);
        if (node)
        {
            TiXmlNode* text = node->FirstChild();
            if (text == NULL)
            {
#if defined(__WINDOWS__)
                _ltoa_s(value, buf, sizeof(buf), 10);
#else
                ltoa(value, buf, 10);
#endif
                text = new Text(buf);
                if (text)
                {
                    node->LinkEndChild(text);
                    return true;
                }
            }
            else if (text->Type() == TiXmlNode::TINYXML_TEXT)
            {
#if defined(__WINDOWS__)
                _ltoa_s(value, buf, sizeof(buf), 10);
#else
                ltoa(value, buf, 10);
#endif
                text->ToText()->SetValue(buf);
                return true;
            }
        }
        return false;
    }

    bool XmlFile::SetDouble(const char* path, double value)
    {
        char buf[1024] = { 0 };
        Node* node = FindOrCreate(path);
        if (node)
        {
            TiXmlNode* text = node->FirstChild();
            if (text == NULL)
            {
#if defined(__WINDOWS__)
                sprintf_s(buf, sizeof(buf), "%f", value);
#else
                sprintf(buf, "%f", value);
#endif
                
                text = new Text(buf);
                if (text)
                {
                    node->LinkEndChild(text);
                    return true;
                }
            }
            else if (text->Type() == TiXmlNode::TINYXML_TEXT)
            {
#if defined(__WINDOWS__)
                sprintf_s(buf, sizeof(buf), "%f", value);
#else
                sprintf(buf, "%f", value);
#endif
                text->ToText()->SetValue(buf);
                return true;
            }
        }
        return false;
    }

}}  // namespace papa::util